package com.trg.flex.frm
{
	import com.trg.flex.MetaDataUtils;
	import com.trg.flex.frm.validation.ArrayValidator;
	import com.trg.flex.frm.validation.EqualValidator;
	import com.trg.flex.frm.validation.ExtDateValidator;
	import com.trg.flex.frm.validation.ExtNumberValidator;
	import com.trg.flex.frm.validation.MultiValidator;
	import com.trg.flex.frm.validation.NotNullValidator;
	
	import mx.collections.ICollectionView;
	import mx.collections.IList;
	import mx.validators.DateValidator;
	import mx.validators.EmailValidator;
	import mx.validators.RegExpValidator;
	import mx.validators.StringValidator;
	import mx.validators.ValidationResult;
	import mx.validators.Validator;
	
	public class FormUtils
	{
		public static function getValidator(object:*, property:String):Validator {
			var type:Class = MetaDataUtils.getPropertyType(object, property);
			var metaData:Object = MetaDataUtils.getPropertyMetaData(object, property);
			if (metaData == null) metaData = {};
			
			var validators:Array = [];
			
			if (type == Number || type == int || type == uint) {
				var numberV:ExtNumberValidator = new ExtNumberValidator();
				numberV.required = false;
				if (type == int || metaData.integer) {
					numberV.domain="int";
				}
				if (metaData.minValue != null) {
					numberV.minValue = metaData.minValue;
					numberV.required = true;
				}
				if (metaData.maxValue != null) {
					numberV.maxValue = metaData.maxValue;
					numberV.required = true;
				}
				if (metaData.fractionalDigits != null) {
					numberV.precision = metaData.fractionalDigits;
				}
				if (metaData.integerDigits != null) {
					numberV.maxIntegerDigits = metaData.integerDigits;
				}
				validators.push(numberV);
			} else if (type == String) {
				var stringV:StringValidator;
				if (metaData.maxLength != null) {
					if (stringV == null) stringV = new StringValidator();
					stringV.maxLength = metaData.maxLength;
					stringV.required = false;
				}
				if (metaData.minLength != null) {
					if (stringV == null) stringV = new StringValidator();
					stringV.minLength = metaData.minLength;
					if (stringV.minLength > 0) stringV.required = true;
				}
				if (stringV != null)
					validators.push(stringV);
				
				if (metaData.email == true) {
					validators.push(new EmailValidator());
					validators[validators.length - 1].required = false;
				}
				if (metaData.regex != null) {
					var regexV:RegExpValidator = new RegExpValidator();
					regexV.expression = metaData.regex;
					regexV.flags = metaData.regexFlags; //this may be null, that's not a problem
					regexV.required = false;
					validators.push(regexV);
				}
			} else if (type == Boolean) {
				var equalV:EqualValidator
				if (metaData.assertTrue) {
					equalV = new EqualValidator();
					equalV.equalTo = true;
					validators.push(equalV);
				} else if (metaData.assertFalse) {
					equalV = new EqualValidator();
					equalV.equalTo = false;
					validators.push(equalV);
				}
			} else if (type == Date) {
				var dateV:DateValidator;
				if (metaData.past) {
					dateV = new ExtDateValidator();
					ExtDateValidator(dateV).past = true;
				} else if (metaData.future) {
					dateV = new ExtDateValidator();
					ExtDateValidator(dateV).future = true;
				} else {
					dateV = new DateValidator()
				}
				dateV.required = false;
				validators.push(dateV);
			} else if (type == Array || MetaDataUtils.typeIs(type, ICollectionView) || MetaDataUtils.typeIs(type, IList)) {
				//size
				var arrayV:ArrayValidator;
				if (metaData.maxLength != null) {
					if (arrayV == null) arrayV = new ArrayValidator();
					arrayV.maxLength = metaData.maxLength;
				}
				if (metaData.minLength != null) {
					if (arrayV == null) arrayV = new ArrayValidator();
					arrayV.minLength = metaData.minLength;
				}
				if (arrayV != null) {
					validators.push(arrayV);
					arrayV.required = false;
				}
			}
			
			if (metaData.notNull == true) {
				validators.push(new NotNullValidator());
			}
			if (metaData.notEmpty == true) {
				if (validators.length == 0) validators.push(new Validator());
				Validator(validators[0]).required = true;
			}
			
			if (validators.length == 0) {
				return null;
			} else if (validators.length == 1) {
				return validators[0];
			} else {
				return new MultiValidator(validators);
			}
		}
		
		private static var numberV:ExtNumberValidator = new ExtNumberValidator();
		private static var stringV:StringValidator = new StringValidator();
		private static var dateV:ExtDateValidator = new ExtDateValidator();
		private static var regexV:RegExpValidator = new RegExpValidator();
		private static var emailV:EmailValidator = new EmailValidator();
		private static var arrayV:ArrayValidator = new ArrayValidator();
		private static var equalV:EqualValidator = new EqualValidator();
		
		public static function validate(type:Class, metaData:Object, value:Object):ValidationResult {
			var result:Array;
			if (metaData == null) metaData = {};
			
			if (metaData.notNull && value == null) {
				return new ValidationResult(true, "", "requiredField",
                                            stringV.requiredFieldError);
			}
			
			if (type == Number || type == int || type == uint) {
				numberV.required = metaData.notEmpty;
				numberV.domain = (type == int || metaData.integer) ? 'int' : 'real';
				numberV.minValue = metaData.minValue;
				numberV.maxValue = metaData.maxValue;
				numberV.precision = metaData.fractionalDigits;
				numberV.maxIntegerDigits = metaData.integerDigits;
				
				result = numberV.validate(value, true).results;
			} else if (type == String) {
				stringV.required = metaData.notEmpty;
				stringV.maxLength = metaData.maxLength;
				stringV.minLength = metaData.minLength;
				
				result = stringV.validate(value, true).results;
				
				if ((result == null || result.length == 0) && metaData.email == true) {
					emailV.required = false;
					result = result = emailV.validate(value, true).results;
				}
				if ((result == null || result.length == 0) && metaData.regex != null) {
					regexV.expression = metaData.regex;
					regexV.flags = metaData.regexFlags; //this may be null, that's not a problem
					regexV.required = false;
					result = regexV.validate(value, true).results;
				}
			} else if (type == Boolean) {
				if (metaData.assertTrue) {
					equalV.equalTo = true;
					result = equalV.validate(value, true).results;
				} else if (metaData.assertFalse) {
					equalV.equalTo = false;
					result = equalV.validate(value, true).results;
				}
			} else if (type == Date) {
				dateV.required = metaData.notEmpty;
				dateV.past = metaData.past;
				dateV.future = metaData.future;
				result = dateV.validate(value, true).results;
			} else if (type == Array || MetaDataUtils.typeIs(type, ICollectionView) || MetaDataUtils.typeIs(type, IList)) {
				arrayV.required = metaData.notEmpty;
				arrayV.maxLength = metaData.maxLength;
				arrayV.minLength = metaData.minLength;
				result = arrayV.validate(value, true).results;
			} else {
				return validate(String, metaData, value);
			}
			
			if (result == null || result.length == 0) {
				return new ValidationResult(false);
			} else {
				return ValidationResult(result[0]);
			}
		} 
		
		public static function needsValidation(type:Class, metaData:Object):Boolean {
			var result:Array;
			
			if (metaData != null) {
				for (var prop:* in metaData) {
					return true;
				}
			}
			
			if (type == Number || type == int || type == uint || Date) {
				return true;
			}
			
			return false;
		} 
		
	}
}